import mongoose from 'mongoose';
import { Award } from './award';
import { Setting } from './setting';
import { TEMPLATE_IDS } from '../config';
import { BookList } from './booklist';
import { sendWxTemplateMsg } from '../utils/weixin/message';
import { transPasswordToHash, comparePassword } from '../utils/password';
import _ from 'lodash';

const UserSchema = new mongoose.Schema(
  {
    username: {
      type: String,
      required: true
    },
    password: String,
    mobile: {
      type: String,
      sparse: true,
      unique: true
    },
    avatar: String,
    identity: Number, // 区分用户是普通用户还是系统管理员，1：微书用户，2：系统管理员
    source: String, // 注册来源 1: 微信公众号, 2: 微信公众号， 3：手机注册
    openid: {
      type: String,
      sparse: true,
      unique: true
    },
    amount: 0, // 书币数量
    member: {
      type: mongoose.Schema.Types.ObjectId,
      ref: 'Member'
    }, // 会员信息
    setting: {
      updateNotice: Boolean,
      reader: {
        fontSize: Number,
        fontFamily: String,
        bright: Number,
        mode: String, // 模式
        overPage: 0 // 0表示左右翻页模式，1表示上下翻页模式
      },
      autoBuy: {
        type: Boolean,
        default: true
      } // 是否自动购买下一章
    },
    read_time: {
      // 阅读时长-毫秒数
      type: Number,
      default: 0
    },
    has_exchange: Boolean, // 书币是否已经兑换
    tags: [String], // 用户标签
    remark: String, // 用户备注
    create_time: Date
  },
  { versionKey: false }
);

UserSchema.index({ openid: 1 }, { sparse: true, unique: true });
UserSchema.index({ mobile: 1 }, { sparse: true, unique: true });

/**
 * 用户名或者邮箱查重
 * @param {String} filed 需要被验证的字段
 * @param {String} value 需要被验证的字段的值
 * @param {*} self 去否忽略自己开始验证
 */
UserSchema.statics.isRepeat = async function (filed, value, self) {
  const query = {};
  query[filed] = value;
  // 忽略admin用户
  query.identity = { $ne: 2 };
  if (self) {
    const users = await User.find(query, '_id');
    return users.length >= 2;
  } else {
    return !!(await User.findOne(query, '_id'));
  }
};

/**
 * 增加用户书币数的静态函数
 * @param {String} 用户id
 * @param {Number} 需要增加的阅币数
 */
UserSchema.statics.addAmount = async function (userid, num, des) {
  if (userid && num) {
    let current = await this.findById(userid);
    if (current) {
      let updateResult = await this.updateOne(
        { _id: userid },
        { $set: { amount: parseInt(current.amount + num) } }
      );
      // 新奖励记录
      await Award.create({
        userid: mongoose.Types.ObjectId(userid),
        des,
        amount: num,
        create_time: new Date()
      });
      if (updateResult.ok == 1 && updateResult.nModified == 1) {
        return true;
      } else {
        console.log('发放书币时更新失败', { userid, num, err: updateResult });
        return false;
      }
    } else {
      console.log('发放书币时找不到此用户', { userid, num });
      return false;
    }
  } else {
    console.log('发放书币时参数错误', { userid, num });
    return false;
  }
};

/**
 * 减少用户书币数的静态函数
 * @param {String} 用户id
 * @param {Number} 需要减少的阅币数
 */
UserSchema.statics.reduceAmount = async function (userid, num) {
  if (userid && num) {
    let current = await this.findById(userid);
    if (current) {
      let amount = parseInt(current.amount - num);
      if (amount >= 0) {
        let updateResult = await this.updateOne({ _id: userid }, { $set: { amount: amount } });
        if (updateResult.ok && updateResult.nModified == 1) {
          return true;
        } else {
          console.log('扣除书币时更新失败', { userid, num, err: updateResult });
          return false;
        }
      } else {
        console.log('扣除书币时书币不足', { userid, num, amount: current.amount });
        return false;
      }
    } else {
      console.log('扣除书币时用户不存在', { userid, num });
      return false;
    }
  } else {
    console.log('扣除书币时参数错误', { userid, num });
    return false;
  }
};

/**
 * 发送模板消息
 * @param userid {String} 用户id
 * @param type {String} 发送消息的类型，比如好友接受邀请的通知，或者书籍解锁成功的通知
 */
UserSchema.statics.sendMessage = async function (userid, type, data, extra) {
  // eslint-disable-next-line no-async-promise-executor
  return new Promise(async (resolve, reject) => {
    if (!(userid && type && data)) {
      console.log('发送模板消息时参数错误', JSON.stringify({ userid, type, data, extra }));
      reject({ ok: false, msg: '参数错误' });
      return false;
    }
    const current = await this.findById(userid, 'openid setting');
    if (!current) {
      console.log('发送模板消息时找不到此用户', JSON.stringify({ userid, type, data, extra }));
      reject({ ok: false, msg: '用户不存在' });
      return false;
    }
    // 如果用户屏蔽了通知，则跳过发送
    if (!_.get(current, 'setting.updateNotice', false)) {
      console.log('发送模板消息时找用户屏蔽了消息', JSON.stringify({ userid, type, data, extra }));
      resolve({ ok: true, msg: '跳过发送' });
      return false;
    }
    if (type === 'accept') {
      // 检查是否打开了设置
      const setting = await Setting.findOne({ key: 'template_message_setting' }, 'value');
      if (!setting || !setting.value || JSON.parse(setting.value)['share'] !== 'true') {
        console.log('暂未打开好友邀请消息提示的设置');
        return false;
      }
      // TODO 待实现
    } else if (type === 'secret') {
      // 秘钥解锁成功消息通知
      const setting = await Setting.findOne({ key: 'template_message_setting' }, 'value');
      if (!setting || !setting.value || JSON.parse(setting.value)['secret'] !== 'true') {
        console.log('暂未打开秘钥解锁消息提示的设置');
        return false;
      }
      if (!extra.bookid) {
        console.log('发送秘钥解锁成功消息时bookid不存在', JSON.stringify({ userid, type, data, extra }));
        reject({ ok: false, msg: '发送秘钥解锁成功消息时bookid不存在' });
        return false;
      }
      try {
        // TODO 待实现
      } catch (err) {
        reject({ ok: false, msg: '发送模板消息失败', err });
      }
    } else if (type === 'book-update') {
      // 书籍更新成功消息通知
      if (!extra.bookid) {
        console.log('发送书籍更新模板消息时bookid不存在', JSON.stringify({ userid, type, data, extra }));
        reject({ ok: false, msg: '发送书籍更新模板消息时bookid不存在' });
        return false;
      }
      sendWxTemplateMsg(
        current.openid,
        TEMPLATE_IDS.book_update,
        `pages/reader/index?book=${extra.bookid}&chapter=${extra.chapter}`,
        data
      )
        .then(async res => {
          if (res.errcode === 0) {
            resolve({ ok: true, msg: '发送模板消息成功' });
          } else {
            console.log(
              '模板消息发送失败',
              JSON.stringify({
                template_id: TEMPLATE_IDS.book_update,
                url: `pages/reader/index?book=${extra.bookid}&chapter=${extra.chapter}`,
                data,
                openid: current.openid
              })
            );
            // 设置书籍重新订阅
            await BookList.updateOne(
              {
                userid: mongoose.Types.ObjectId(userid),
                'books.bookid': mongoose.Types.ObjectId(extra.bookid)
              },
              { $set: { 'books.$.rss': 0 } }
            );
            reject({ ok: false, msg: res.errmsg });
          }
        })
        .catch(err => {
          reject({ ok: false, msg: '发送模板消息失败', err });
        });
    } else if (type === 'comment') {
      // 评论回复消息提示
      if (!extra.bookid) {
        console.log('发送书评模板消息时bookid不存在', JSON.stringify({ userid, type, data, extra }));
        reject({ ok: false, msg: '发送书评模板消息时bookid不存在' });
        return false;
      }
      //  TODO 待实现
    }
  });
};

// 存储密码之前将其转换成hash值
UserSchema.pre('save', function (next) {
  var user = this;
  //产生密码hash当密码有更改的时候(或者是新密码)
  if (!user.isModified('password')) return next();
  // 使用hash覆盖明文密码
  user.password = transPasswordToHash(user.password);
  next();
});

/**
 * 检验用户密码的合法性的实例方法
 */
UserSchema.methods.checkPassword = async function (candidatePassword) {
  return comparePassword(candidatePassword, this.password);
};

let User = mongoose.model('User', UserSchema);

export { User };
